package com.nwpu.coursesupport.tool;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author Harry
 *
 */
public final class StringUtil {

	/**
	 * Empty string
	 */
	public static final String EMPTY = "";

	/**
	 * Index not found
	 */
	public static final int INDEX_NOT_FOUND = -1;

	/**
	 * Equals sign
	 */
	public static final String EQUALS_SIGN = "=";

	/**
	 * Comma
	 */
	public static final String COMMA = ",";

	/**
	 * True string
	 */
	public static final String TRUE_STRING = "true";

	/**
	 * False string
	 */
	public static final String FALSE_STRING = "false";

	/**
	 * Null string
	 */
	public static final String NULL_STRING = "null";

	/**
	 * Number Regexp pattern
	 */
	private static final Pattern NUMBER_PATTERN = Pattern.compile("^-?\\d+(.\\d+)?");

	/**
	 * Prevent from creating instance
	 */
	private StringUtil() {
	}

	/**
	 * Check if a string is empty or null
	 * 
	 * @param str the string to check
	 * @return
	 */
	public static boolean isEmpty(String str) {
		return str == null || str.isEmpty();
	}

	/**
	 * Check if a string is not empty and null
	 * 
	 * @param str the string to check
	 * @return
	 */
	public static boolean isNotEmpty(String str) {
		return !isEmpty(str);
	}

	/**
	 * Check if strings have empty or null
	 * 
	 * @param str the string to check
	 * @param strs the strings to check
	 * @return
	 */
	public static boolean hasEmpty(String str, String... strs) {
		if (isEmpty(str)) {
			return true;
		}
		for (String s : strs) {
			if (isEmpty(s)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Returns a string with any leading and trailing whitespace removed
	 * 
	 * @param str the string to trim
	 * @return
	 */
	public static String trim(String str) {
		if (isEmpty(str)) {
			return str;
		}
		return str.trim();
	}
	
	/**
	 * Returns a string with leading whitespace removed
	 * 
	 * @param str the string to trim
	 * @return
	 */
	public static String trimStart(String str) {
		if (isEmpty(str)) {
			return str;
		}
		int i = 0;
		while (i < str.length() && str.charAt(i) == ' ') {
			i++;
		}
		return str.substring(i);
	}
	
	/**
	 * Returns a string with trailing whitespace removed
	 * 
	 * @param str the string to trim
	 * @return
	 */
	public static String trimEnd(String str) {
		if (isEmpty(str)) {
			return str;
		}
		int i = str.length() - 1;
		while (i >= 0 && str.charAt(i) == ' ') {
			i--;
		}
		i++;
		return str.substring(0, i);
	}

	/**
	 * Convert a string to map("," as item separator, "=" as key separator)
	 * 
	 * @param str the string to be converted
	 * @return
	 */
	public static Map<String, Object> toMap(String str) {
		return toMap(str, COMMA, EQUALS_SIGN);
	}

	/**
	 * Convert a string to map
	 * 
	 * @param str the string to be converted
	 * @param itemSeparator the item separator
	 * @param keySeparator the key separator
	 * @return
	 */
	public static Map<String, Object> toMap(String str, String itemSeparator, String keySeparator) {
		if (isEmpty(itemSeparator)) {
			throw new IllegalArgumentException("itemSeparator cannot be null or empty");
		}
		if (isEmpty(keySeparator)) {
			throw new IllegalArgumentException("keySeparator cannot be null or empty");
		}
		Map<String, Object> map = new HashMap<String, Object>();
		if (isNotEmpty(str)) {
			int index = INDEX_NOT_FOUND;
			for (String item : str.split(itemSeparator)) {
				index = item.indexOf(keySeparator);
				if (index == INDEX_NOT_FOUND) {
					continue;
				}
				map.put(item.substring(0, index), item.substring(index + 1));
			}
		}
		return map;
	}

	/**
	 * Check if a string is a number
	 * 
	 * @param str the str to check
	 * @return
	 */
	public static boolean isNumber(String str) {
		return NUMBER_PATTERN.matcher(str).matches();
	}

	/**
	 * Strips the given start from the start of string
	 * 
	 * @param str the string to strip
	 * @param start the start
	 * @return
	 */
	public static String stripStart(String str, String start) {
		if (hasEmpty(str, start)) {
			return str;
		}
		int index = str.indexOf(start);
		if (index != INDEX_NOT_FOUND) {
			return str.substring(start.length());
		}
		return str;
	}

	/**
	 * Strips the given end from the end of string
	 * 
	 * @param str the string to strip
	 * @param end the end
	 * @return
	 */
	public static String stripEnd(String str, String end) {
		if (hasEmpty(str, end)) {
			return str;
		}
		int index = str.lastIndexOf(end);
		if (index != INDEX_NOT_FOUND) {
			return str.substring(0, index);
		}
		return str;
	}

	/**
	 * Escapes a string using java string rule
	 * 
	 * @param str the string to escape
	 * @return
	 */
	public static String escapeJava(String str) {
		if (isEmpty(str)) {
			return str;
		}
		StringBuilder escapeStr = new StringBuilder();
		for (char c : str.toCharArray()) {
			switch (c) {
				case '\'':
					escapeStr.append("\'");
					break;
				case '"':
					escapeStr.append("\\\"");
					break;
				case '\\':
					escapeStr.append("\\\\");
					break;
				default:
					escapeStr.append(c);
					break;
			}
		}
		return escapeStr.toString();
	}

	/**
	 * Unescapes a string using java string rule
	 * 
	 * @param str the string to unescape
	 * @return
	 */
	public static String unescapeJava(String str) {
		if (isEmpty(str)) {
			return str;
		}
		StringBuilder unescapeStr = new StringBuilder();
		boolean hadSlash = false;
		for (char c : str.toCharArray()) {
			if (hadSlash) {
				hadSlash = false;
				switch (c) {
					case '\'':
						unescapeStr.append('\'');
						break;
					case '"':
						unescapeStr.append('"');
						break;
					case '\\':
						unescapeStr.append('\\');
						break;
					case 'r':
						unescapeStr.append('\r');
						break;
					case 'f':
						unescapeStr.append('\f');
						break;
					case 't':
						unescapeStr.append('\t');
						break;
					case 'n':
						unescapeStr.append('\n');
						break;
					case 'b':
						unescapeStr.append('\b');
						break;
					default:
						unescapeStr.append(c);
						break;
				}
				continue;
			} else if (c == '\\') {
				hadSlash = true;
				continue;
			}
			unescapeStr.append(c);
		}
		return unescapeStr.toString();
	}

	/**
	 * Casts a string to long
	 * 
	 * @param str the string to cast
	 * @return
	 */
	public static long toSafeLong(String str) {
		try {
			if (StringUtil.isNotEmpty(str)) {
				return Long.parseLong(str);
			}
		} catch (NumberFormatException e) {
		}
		return 0;
	}
	
	/**
	 * Casts a string to int
	 * 
	 * @param str the string to cast
	 * @return
	 */
	public static int toSafeInteger(String str) {
		try {
			if (StringUtil.isNotEmpty(str)) {
				return Integer.parseInt(str);
			}
		} catch (NumberFormatException e) {
		}
		return 0;
	}
}

